import functools
import json
import sqlite3
from datetime import datetime
from typing import Callable, Any, Dict
from fastapi import Request
import aiohttp
import os

DB_PATH = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'appdata', 'sqlite3')
GLOBAL_USER_ID = "202506070001"

def log_operation(action: str = None):
    """
    操作日志装饰器
    :param action: 操作类型，如果不指定则使用函数名
    """
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        async def wrapper(*args, **kwargs):
            # 获取请求对象
            request = next((arg for arg in args if isinstance(arg, Request)), None)
            
            # 获取用户ID
            user_id = GLOBAL_USER_ID or kwargs.get('user_id')
            if not user_id and request:
                # 从请求中获取用户信息
                try:
                    config = Config()
                    cookie = config.get_cookies()
                    if cookie:
                        async with aiohttp.ClientSession() as session:
                            headers = {
                                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
                                'Cookie': cookie
                            }
                            async with session.get('https://api.bilibili.com/x/web-interface/nav', headers=headers) as response:
                                if response.status == 200:
                                    data = await response.json()
                                    if data['code'] == 0 and data['data']['isLogin']:
                                        user_id = str(data['data']['mid'])
                except:
                    pass

            # 获取任务ID（优先参数，其次返回值）
            task_id = kwargs.get('task_id')
            
            # 构建操作详情
            detail = {
                'args': [str(arg) for arg in args if not isinstance(arg, (Request, BackgroundTasks))],
                'kwargs': {k: str(v) for k, v in kwargs.items() if k not in ['request', 'background_tasks']}
            }
            
            # 执行原函数，捕获返回值
            result = await func(*args, **kwargs)
            # 如果返回值中有task_id，自动补全
            if not task_id and isinstance(result, dict) and 'task_id' in result:
                task_id = result['task_id']
            
            # 记录操作日志
            try:
                conn = sqlite3.connect(DB_PATH)
                c = conn.cursor()
                c.execute(
                    "INSERT INTO operation_log (user_id, task_id, action, detail, ip, created_at) VALUES (?, ?, ?, ?, ?, ?)",
                    (
                        user_id,
                        task_id,
                        action or func.__name__,
                        json.dumps(detail, ensure_ascii=False),
                        request.client.host if request else None,
                        datetime.now()
                    )
                )
                conn.commit()
                conn.close()
            except Exception as e:
                print(f"记录操作日志失败: {str(e)}")
            
            return result
        return wrapper
    return decorator

# 新增：任务AOP装饰器
def log_task(task_type: str = None):
    """
    任务记录装饰器，自动将任务信息写入任务表
    :param task_type: 任务类型
    """
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        async def wrapper(*args, **kwargs):
            request = next((arg for arg in args if isinstance(arg, Request)), None)
            user_id = GLOBAL_USER_ID or kwargs.get('user_id')
            if not user_id and request:
                try:
                    config = Config()
                    cookie = config.get_cookies()
                    if cookie:
                        async with aiohttp.ClientSession() as session:
                            headers = {
                                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
                                'Cookie': cookie
                            }
                            async with session.get('https://api.bilibili.com/x/web-interface/nav', headers=headers) as response:
                                if response.status == 200:
                                    data = await response.json()
                                    if data['code'] == 0 and data['data']['isLogin']:
                                        user_id = str(data['data']['mid'])
                except:
                    pass
            result = await func(*args, **kwargs)
            # 自动写入任务表
            try:
                task_id = None
                params = None
                if isinstance(result, dict) and 'task_id' in result:
                    task_id = result['task_id']
                    params = {}
                    for k, v in kwargs.items():
                        if k in ['request', 'background_tasks', 'user_id']:
                            continue
                        # 处理不可序列化对象
                        if hasattr(v, 'filename'):
                            params[k] = f"<UploadFile: {v.filename}>"
                        else:
                            try:
                                json.dumps(v)
                                params[k] = v
                            except:
                                params[k] = str(v)
                if task_id:
                    conn = sqlite3.connect(DB_PATH)
                    c = conn.cursor()
                    c.execute(
                        "INSERT OR IGNORE INTO task (id, user_id, type, params, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)",
                        (task_id, user_id, task_type or func.__name__, json.dumps(params, ensure_ascii=False), 'waiting', datetime.now(), datetime.now())
                    )
                    conn.commit()
                    conn.close()
            except Exception as e:
                print(f"记录任务信息失败: {str(e)}")
            return result
        return wrapper
    return decorator 